package org.fjsei.yewu.config;

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Set;
import java.util.HashSet;

@Component
public class SqlGenerator {

    public void generateSqlScripts(String outputDir) throws IOException {
        // 创建输出目录
        File directory = new File(outputDir);
        if (!directory.exists()) {
            directory.mkdirs();
        }

        // 扫描所有实体类
        Set<Class<?>> entityClasses = scanEntityClasses("org.fjsei.yewu");

        // 生成创建脚本
        File createFile = new File(outputDir + "/01-create-tables.sql");
        generateCreateScript(entityClasses, createFile);

        // 生成删除脚本
        File dropFile = new File(outputDir + "/99-drop-tables.sql");
        generateDropScript(entityClasses, dropFile);

        // 生成说明文档
        generateDocumentation(outputDir, entityClasses);
    }

    private void generateCreateScript(Set<Class<?>> entityClasses, File outputFile) throws IOException {
        try (FileWriter writer = new FileWriter(outputFile)) {
            writer.write("-- 创建表脚本\n");
            writer.write("-- 生成时间: " + new java.util.Date() + "\n");
            writer.write("-- 数据库方言: PostgreSQL\n\n");
            
            for (Class<?> entityClass : entityClasses) {
                generateTableCreateSQL(entityClass, writer);
                writer.write("\n");
            }
        }
    }

    private void generateDropScript(Set<Class<?>> entityClasses, File outputFile) throws IOException {
        try (FileWriter writer = new FileWriter(outputFile)) {
            writer.write("-- 删除表脚本\n");
            writer.write("-- 生成时间: " + new java.util.Date() + "\n");
            writer.write("-- 警告: 此脚本将删除所有表，请谨慎使用!\n\n");
            
            for (Class<?> entityClass : entityClasses) {
                String tableName = getTableName(entityClass);
                writer.write("DROP TABLE IF EXISTS " + tableName + " CASCADE;\n");
            }
        }
    }

    private void generateTableCreateSQL(Class<?> entityClass, FileWriter writer) throws IOException {
        String tableName = getTableName(entityClass);
        writer.write("-- 表: " + entityClass.getSimpleName() + "\n");
        writer.write("CREATE TABLE " + tableName + " (\n");
        
        Field[] fields = entityClass.getDeclaredFields();
        boolean first = true;
        
        for (Field field : fields) {
            if (shouldSkipField(field)) {
                continue;
            }
            
            if (!first) {
                writer.write(",\n");
            }
            first = false;
            
            String columnName = getColumnName(field);
            String columnType = getColumnType(field);
            String constraints = getColumnConstraints(field);
            
            writer.write("    " + columnName + " " + columnType + constraints);
        }
        
        writer.write("\n);\n");
    }

    private String getTableName(Class<?> entityClass) {
        Entity entityAnnotation = entityClass.getAnnotation(Entity.class);
        Table tableAnnotation = entityClass.getAnnotation(Table.class);
        
        if (tableAnnotation != null && !tableAnnotation.name().isEmpty()) {
            return tableAnnotation.name();
        } else if (entityAnnotation != null && !entityAnnotation.name().isEmpty()) {
            return entityAnnotation.name();
        } else {
            return entityClass.getSimpleName().toLowerCase();
        }
    }

    private String getColumnName(Field field) {
        Column columnAnnotation = field.getAnnotation(Column.class);
        if (columnAnnotation != null && !columnAnnotation.name().isEmpty()) {
            return columnAnnotation.name();
        }
        return field.getName().toLowerCase();
    }

    private String getColumnType(Field field) {
        Class<?> type = field.getType();
        
        if (type == String.class) {
            Column columnAnnotation = field.getAnnotation(Column.class);
            if (columnAnnotation != null && columnAnnotation.length() > 0) {
                return "VARCHAR(" + columnAnnotation.length() + ")";
            }
            return "VARCHAR(255)";
        } else if (type == Integer.class || type == int.class) {
            return "INTEGER";
        } else if (type == Long.class || type == long.class) {
            return "BIGINT";
        } else if (type == Boolean.class || type == boolean.class) {
            return "BOOLEAN";
        } else if (type == java.util.Date.class || type == java.time.LocalDateTime.class) {
            return "TIMESTAMP";
        } else if (type == java.math.BigDecimal.class) {
            return "DECIMAL(19,2)";
        } else if (type.isEnum()) {
            return "VARCHAR(50)";
        } else {
            return "VARCHAR(255)";
        }
    }

    private String getColumnConstraints(Field field) {
        StringBuilder constraints = new StringBuilder();
        
        // 主键约束
        if (field.getAnnotation(Id.class) != null) {
            constraints.append(" PRIMARY KEY");
            
            // 自增约束
            GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
            if (generatedValue != null && generatedValue.strategy() == GenerationType.IDENTITY) {
                constraints.append(" GENERATED ALWAYS AS IDENTITY");
            }
        }
        
        // 非空约束
        Column columnAnnotation = field.getAnnotation(Column.class);
        if (columnAnnotation != null && !columnAnnotation.nullable()) {
            constraints.append(" NOT NULL");
        }
        
        // 唯一约束
        if (columnAnnotation != null && columnAnnotation.unique()) {
            constraints.append(" UNIQUE");
        }
        
        return constraints.toString();
    }

    private boolean shouldSkipField(Field field) {
        // 跳过静态字段、瞬时字段等
        return java.lang.reflect.Modifier.isStatic(field.getModifiers()) ||
               java.lang.reflect.Modifier.isTransient(field.getModifiers()) ||
               field.getAnnotation(jakarta.persistence.Transient.class) != null;
    }

    private Set<Class<?>> scanEntityClasses(String basePackage) {
        ClassPathScanningCandidateComponentProvider scanner = 
            new ClassPathScanningCandidateComponentProvider(false);
        
        scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
        
        Set<Class<?>> entityClasses = new java.util.HashSet<>();
        
        for (org.springframework.beans.factory.config.BeanDefinition bd : 
             scanner.findCandidateComponents(basePackage)) {
            try {
                Class<?> clazz = Class.forName(bd.getBeanClassName());
                entityClasses.add(clazz);
            } catch (ClassNotFoundException e) {
                System.err.println("无法加载类: " + bd.getBeanClassName());
            }
        }
        
        return entityClasses;
    }

    private void generateDocumentation(String outputDir, Set<Class<?>> entityClasses) 
            throws IOException {
        File docFile = new File(outputDir + "/00-README.md");
        try (FileWriter writer = new FileWriter(docFile)) {
            writer.write("# 数据库SQL脚本\n\n");
            writer.write("生成时间: " + new java.util.Date() + "\n\n");
            writer.write("## 文件说明\n\n");
            writer.write("- `01-create-tables.sql`: 创建所有表的SQL脚本\n");
            writer.write("- `99-drop-tables.sql`: 删除所有表的SQL脚本（谨慎使用）\n\n");
            writer.write("## 实体列表\n\n");
            
            for (Class<?> entityClass : entityClasses) {
                Entity entityAnnotation = entityClass.getAnnotation(Entity.class);
                String tableName = entityAnnotation.name();
                if (tableName.isEmpty()) {
                    tableName = entityClass.getSimpleName().toLowerCase();
                }
                writer.write("- " + entityClass.getSimpleName() + " -> " + tableName + "\n");
            }
            
            writer.write("\n## 使用说明\n\n");
            writer.write("1. 在生产环境执行前，请仔细检查SQL语句\n");
            writer.write("2. 建议先在测试环境验证脚本正确性\n");
            writer.write("3. 执行顺序：先执行创建脚本，再执行数据迁移（如有）\n");
        }
    }
}

/*
使用方法：
# 生成SQL脚本
./gradlew generateSql

# 或者使用另一个任务
./gradlew generateProductionSql
*/